package com.coin.exchange.otcbtc.api.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.coin.exchange.otcbtc.api.OtcbtcAuthApi;
import com.coin.exchange.util.HttpUtil;

/**
 * w5f3nbx75poodyix
 * @author duyuchong
 *
 */
@Service
public class OtcbtcAuthApiImpl implements OtcbtcAuthApi {

	private static final String ALGORITHM_HMACSHA256 = "HmacSHA256";

	@Value("${otcbtc.api.url}")
	private String URL_PREX = "https://bb.otcbtc.com";
	
	private static final String USERS_URL = "/api/v2/users/me";
	private static final String LIST_ORDERS_URL = "/api/v2/orders";
	private static final String LIST_ORDER_URL = "/api/v2/order";
	private static final String CREATE_ORDER_URL = "/api/v2/orders";
	private static final String CANCEL_ORDER_URL = "/api/v2/order/delete";
	private static final String CANCEL_ORDERS_URL = "/api/v2/orders/clear";
	private static final String MY_TRADES_URL = "/api/v2/trades/my";
	
	@Override
	public String getUsers(String accessKey, String apiSecret) throws Exception {
		String url = URL_PREX + USERS_URL;
		String payload = "GET|" + USERS_URL + "|access_key=" + accessKey;
		String signature = generateSignature(payload, apiSecret);
		Map<String, Object> params = new HashMap<>();
		params.put("access_key", accessKey);
		params.put("signature", signature);
		String res = HttpUtil.httpGet(url, params);
		return res;
	}

	@Override
	public String listOrders(String accessKey, String apiSecret, String market, String state, Integer limit, Integer page, String orderBy) throws Exception {
		String url = URL_PREX + LIST_ORDERS_URL;
		Map<String, Object> params = new HashMap<>();
		params.put("access_key", accessKey);
		params.put("market", market);
		if (state != null) params.put("state", state);
		if (limit != null) params.put("limit", limit);
		if (page != null) params.put("page", page);
		if (orderBy != null) params.put("order_by", orderBy);
		String payload = generatePayload("GET", LIST_ORDERS_URL, params);
		params.put("signature", generateSignature(payload, apiSecret));
		String res = HttpUtil.httpGet(url, params);
		return res;
	}

	@Override
	public String listOrder(String accessKey, String apiSecret, Long orderId) throws Exception {
		String url = URL_PREX + LIST_ORDER_URL;
		Map<String, Object> params = new HashMap<>();
		params.put("access_key", accessKey);
		params.put("id", orderId);
		String payload = generatePayload("GET", LIST_ORDER_URL, params);
		params.put("signature", generateSignature(payload, apiSecret));
		String res = HttpUtil.httpGet(url, params);
		return res;
	}

	@Override
	public String createOrder(String accessKey, String apiSecret, String market, String side, Double volume, Double price, String ordType) throws Exception {
		String url = URL_PREX + CREATE_ORDER_URL;
		Map<String, Object> params = new HashMap<>();
		params.put("access_key", accessKey);
		params.put("market", market);
		params.put("side", side);
		params.put("volume", volume);
		if (price != null) params.put("price", price);
		if (ordType != null) params.put("ord_type", ordType);
		String payload = generatePayload("POST", CREATE_ORDER_URL, params);
		params.put("signature", generateSignature(payload, apiSecret));
		String res = HttpUtil.httpPostFormData(url, params);
		return res;
	}

	@Override
	public String cancelOrder(String accessKey, String apiSecret, Long orderId) throws Exception {
		String url = URL_PREX + CANCEL_ORDER_URL;
		Map<String, Object> params = new HashMap<>();
		params.put("access_key", accessKey);
		params.put("id", orderId);
		String payload = generatePayload("POST", CANCEL_ORDER_URL, params);
		params.put("signature", generateSignature(payload, apiSecret));
		String res = HttpUtil.httpPostFormData(url, params);
		return res;
	}

	@Override
	public String cancelOrders(String accessKey, String apiSecret, String side) throws Exception {
		String url = URL_PREX + CANCEL_ORDERS_URL;
		Map<String, Object> params = new HashMap<>();
		params.put("access_key", accessKey);
		if (side != null) params.put("side", side);
		String payload = generatePayload("POST", CANCEL_ORDERS_URL, params);
		params.put("signature", generateSignature(payload, apiSecret));
		String res = HttpUtil.httpPostFormData(url, params);
		return res;
	}

	@Override
	public String getMyTrades(String accessKey, String apiSecret, String market, Integer limit, Long timestamp, String from, String to, String orderBy) throws Exception {
		String url = URL_PREX + MY_TRADES_URL;
		Map<String, Object> params = new HashMap<>();
		params.put("access_key", accessKey);
		params.put("market", market);
		if (limit != null) params.put("limit", limit);
		if (timestamp != null) params.put("timestamp", timestamp);
		if (from != null) params.put("from", from);
		if (to != null) params.put("to", to);
		if (orderBy != null) params.put("order_by", orderBy);
		String payload = generatePayload("GET", MY_TRADES_URL, params);
		params.put("signature", generateSignature(payload, apiSecret));
		String res = HttpUtil.httpGet(url, params);
		return res;
	}

	private String generatePayload(String method, String url, Map<String, Object> params) {
		List<String> list = new ArrayList<>();
		for (String key : params.keySet()) {
			list.add(key + "=" + params.get(key));
		}
		String [] arrayToSort = list.toArray(new String[list.size()]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);

		StringBuffer payload = new StringBuffer();
		payload.append(method).append("|").append(url).append("|");
		for (int i = 0; i < arrayToSort.length; i ++) {
			payload.append(arrayToSort[i]).append("&");
        }
		return payload.substring(0, payload.length() - 1);
	}
	
	private String generateSignature(String payload, String apiSecret) throws Exception {
		SecretKeySpec key = new SecretKeySpec((apiSecret).getBytes("UTF-8"), ALGORITHM_HMACSHA256);
		Mac mac = Mac.getInstance(ALGORITHM_HMACSHA256);
        mac.init(key);

        byte[] bytes = mac.doFinal(payload.getBytes("ASCII"));

        StringBuffer hash = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(0xFF & bytes[i]);
            if (hex.length() == 1) {
                hash.append('0');
            }
            hash.append(hex);
        }
		return hash.toString();
	}
	
}
